
package com.reader.core.redis;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.reader.core.utils.FastJsonUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
public class RedisDao {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 根据key获取缓存中的值.
     * @param key
     */
    public String get(String key) {
        return this.stringRedisTemplate.opsForValue().get(key);
    }

    /**
     * 设置k-v.
     * @param key
     * @param value
     */
    public void save(String key, String value) {
        this.stringRedisTemplate.opsForValue().set(key, value);
    }

    /**
     * redis 保存JSON对象.
     * @param key
     * @param value
     */
    public void save(String key, Object value) {
        String jsonStr= FastJsonUtil.toJSONString(value);
        this.stringRedisTemplate.opsForValue().set(key, jsonStr);
    }

    /**
     * 设置带过期时间的Redis.
     * @param key
     * @param value
     * @param timeout
     * @param unit
     */
    public void save(String key, Object value,long timeout, TimeUnit unit) {
        String jsonStr= FastJsonUtil.toJSONString(value);
        this.stringRedisTemplate.opsForValue().set(key, jsonStr,timeout,unit);
    }

    /**
     * 批量写String类型的值.
     *
     * @param paramList 命令列表.
     */
    public void saveValueBatch(final List<RedisParam> paramList){
        RedisCallback<List<Object>> pipelineCallback = new RedisCallback<List<Object>>() {
            @Nullable
            @Override
            public List<Object>  doInRedis(RedisConnection connection) throws DataAccessException {
                connection.openPipeline();
                for (RedisParam redisParam:paramList){
                    connection.set(redisParam.getKey().getBytes(),redisParam.getStringValue().getBytes());
                }
                return connection.closePipeline();
            }
        };
        stringRedisTemplate.execute(pipelineCallback);
    }

    /**
     * 批量获取tring类型的值.
     *
     * @param keyList 命令列表.
     */
    public List<String> getValueBatch(final List<String> keyList){
        RedisCallback<List<Object>> pipelineCallback = new RedisCallback<List<Object>>() {
            @Nullable
            @Override
            public List<Object>  doInRedis(RedisConnection connection) throws DataAccessException {
                connection.openPipeline();
                for (String key:keyList){
                    connection.get(key.getBytes());
                }
                return connection.closePipeline();
            }
        };

        List<Object>retList = stringRedisTemplate.execute(pipelineCallback);

        List<String>valueList = Lists.newArrayList();
        for (Object obj:retList){
            String str = (String) obj;
            if (StringUtils.isNoneBlank(str)){
                valueList.add(str);
            }
        }

        return valueList;
    }

    /**
     * 删除KEY.
     * @param key
     */
    public void delete(String key) {
      stringRedisTemplate.delete(key);
    }

    /**
     *自增1.
     * @param key
     * @return  返回自增后的值
     */
    public Long incr(String key) {
        return  stringRedisTemplate.opsForValue().increment(key,1);
    }

    /**
     *自增n.
     * @param key
     * @return 返回自增后的值
     */
    public Long incrByN(String key,int n) {
        return  stringRedisTemplate.opsForValue().increment(key,n);
    }

    /**
     * 去重入栈
     *
     * @param key
     * @param value
     * @return
     */
    public Long lpushWithDistinct(String key, String value) {
        delete(key);//如果KEY已存在，则先删除
        return stringRedisTemplate.opsForList().leftPush(key, value);
    }

    public Long lpushWithDistinct(String key, Object value) {
        delete(key);//如果KEY已存在，则先删除
        String jsonString= FastJsonUtil.toJSONString(value);
        return stringRedisTemplate.opsForList().leftPush(key, jsonString);
    }

    /**
     * 入栈
     *
     * @param key
     * @param value
     * @return
     */
    public Long lpush(String key, String value) {
        return stringRedisTemplate.opsForList().leftPush(key, value);
    }

    public Long lpush(String key, Object value) {
        String jsonString=FastJsonUtil.toJSONString(value);
        return stringRedisTemplate.opsForList().leftPush(key, jsonString);
    }

    /**
     * 出栈
     *
     * @param key
     * @return
     */
    public String rpopString(String key) {
        return stringRedisTemplate.opsForList().rightPop(key);
    }

    /**
     * 从对列中取出
     * @param key JSONObject 类型
     * @return
     */
   public JSONObject rpopObject(String key) {
         String jsonStr= stringRedisTemplate.opsForList().rightPop(key);
         JSONObject jsonObject= FastJsonUtil.toBean(jsonStr, JSONObject.class);
        return jsonObject;
    }


    /**
     *返回指定泛型对象
     * @param key
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T rpopObject(String key,Class<T> clazz) {
        String jsonStr= stringRedisTemplate.opsForList().rightPop(key);
        T jsonObject= (T) FastJsonUtil.toBean(jsonStr,clazz);
        return jsonObject;
    }

    /**
     * 设置KEY过期时间
     * @param key
     * @param timeout
     * @param unit
     */
    public void setExpireTime(String key,long timeout, TimeUnit unit){
        this.stringRedisTemplate.expire(key,timeout , unit);
    }

    /**
     * 通过Key得到jsonobject对象
     * @param key
     * @return
     */
    public JSONObject getObject(String key) {
        String jsonStr=this.stringRedisTemplate.opsForValue().get(key);
        JSONObject jsonObject=FastJsonUtil.toBean(jsonStr, JSONObject.class);
        return jsonObject;
    }

    /**
     * 通过Key得到指定泛型对象
     * @param key
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T getObject(String key,Class<T> clazz) {
        String jsonStr=this.stringRedisTemplate.opsForValue().get(key);
        T object=(T) FastJsonUtil.toBean(jsonStr,clazz);
        return object;
    }

    /**
     *检查key是否存在，返回boolean值
     * @return
     */
    public boolean  existKey(String key){
       return stringRedisTemplate.hasKey(key);
    }

    /**
     * 返回满足通配符的键值Set
     * @param keysPattern
     * @return
     */
    public Set<String> getKeys(String keysPattern){
        Set<String> values= stringRedisTemplate.keys(keysPattern);
        return values;
    }



    /**
     * 栈/队列长
     *
     * @param key
     * @return
     */
    public Long length(String key) {
        return stringRedisTemplate.opsForList().size(key);
    }

    /**
     * 范围检索
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public List<String> range(String key, Long start, Long end) {
        return stringRedisTemplate.opsForList().range(key, start, end);
    }



    /**
     * 裁剪
     *
     * @param key
     * @param start
     * @param end
     */
    public void trim(String key, long start, int end) {
        stringRedisTemplate.opsForList().trim(key, start, end);
    }

}
